#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include "deviser.h"
#include "gc.h"

cell lisp_read(FILE* in) {
	char c;
	while(isspace(c = fgetc(in)) && !feof(in)); /*puts the first non-white 
						      space character in c*/
	if(feof(in)) return NULL;
	if(c == '(') {
		cell dotsymbol = mk_symbol(".", 1);
		cell* rets = NULL;
		int num_rets = 0;
		cell ret = mk_eol();

		while((c = fgetc(in)) != ')') {
			ungetc(c, in);
			cell s = lisp_read(in);
			if(s != NULL) {
				if(symbolp(&s) && eqp(&s, &dotsymbol)) {
					cell cdr = lisp_read(in);
					if(cdr == NULL) { printf("No cdr for the pair\n"); exit(1); }
					if(lisp_read(in) != NULL) {
						printf("More than one cdr for the pair\n");
						exit(1);
					}
					if(num_rets == 0) {
						printf("No car for the pair\n");
						exit(1);
					}

					ret = cons(rets[num_rets-1], cdr);
					num_rets--;
				} else {
					rets = (cell*) realloc(rets, 
							       sizeof(cell)*(num_rets+1));
					rets[num_rets] = s;
					num_rets++;
				}
			}
		}

		int i;
		for(i = num_rets-1; i >= 0; i--) {
			ret = cons(rets[i], ret);
		}
		return ret;
	} else if(c == ')') {
		ungetc(c, in);
		return NULL;
	} else {
		char* ret = NULL;
		int num_ret = 0;
		ungetc(c, in);
		while(c = fgetc(in), !isspace(c) && c != '(' && c != ')') {
			ret = (char*) realloc(ret, num_ret+1);
			ret[num_ret] = c;
			num_ret++;
		}
		ungetc(c, in);
		int i;
		for(i = 0; i < num_ret; i++) {
			if(!isdigit(ret[i])) return mk_symbol(ret, num_ret);
		}
		ret = (char*) realloc(ret, num_ret+1);
		ret[num_ret] = 0;
		return mk_number(atoi(ret));
	}
}

/*void print_chars(const char* buf, int num, FILE* out) {
	int i;
	for(i = 0; i < num; i++) {
		fputc(buf[i], out);
	}
}*/

void print_symbol(cell c, FILE* out) {
	cell t = symbol_to_string(&c);
	const char* buf = get_str_val(&t);
	fwrite(buf, get_str_len(&t), 1, out);
}

int lisp_print(cell c, FILE* out) {
	if(symbolp(&c)) print_symbol(c, out);
	else if(numberp(&c)) fprintf(out, "%i", number_to_cint(c));
	else if(nullp(&c)) fprintf(out, "() ");
	else if(consp(&c)) {
		fprintf(out, "(");
		while(consp(&c)) {
			lisp_print(car(&c), out);
			if(!enullp(cdr(&c))) fprintf(out, " ");
			c = cdr(&c);
		}
		if(nullp(&c)) {
			fprintf(out, ")");
		} else {
			fprintf(out, ". ");
			lisp_print(c, out);
			fprintf(out, ")");
		}
	} else if(stringp(&c)) {
		printf("\"");
		fwrite(get_str_val(&c), get_str_len(&c), 1, out);
		printf("\"");
	} else if(lfuncp(&c)) {
		fprintf(out, "<Function: %x: ", (unsigned int)c);
		lisp_print(get_code(&c), out);
		fprintf(out, ">");
	} else if(cfuncp(&c)) {
		fprintf(out, "<CFunction: %x>", (unsigned int)c);
	}// else if(undefp(&c)) ; //Do nothing
	else if(boolp(&c)) {
		if(!falsep(&c)) fprintf(out, "true");
		else fprintf(out, "false");
	} 
	else fprintf(out, "<Something Else: %x>", (unsigned int) c);
	return 0;
}

